///////////////////////////////////////////////////////////////////////////////////////////////////
/// \file formic/output/output.h
///
/// \brief   header file for output operations
///
///////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef FORMIC_OUTPUT_HEADER
#define FORMIC_OUTPUT_HEADER

#include<fstream>

#include<boost/shared_ptr.hpp>

#include<formic/exception.h>

namespace formic {

  template <class T> class Output {

    private:

      /// \brief the ouput stream
      boost::shared_ptr<T> _os;

    public:

      template<class U> Output<T> & operator<<(const U & item) {
        if ( _os.get() == 0 )
          throw formic::Exception("Output object currently has no stream");
        (*_os) << item;
        return *this;
      }

      Output<T> & operator<<(std::ostream & (*pf)(std::ostream &)) {
        if ( _os.get() == 0 )
          throw formic::Exception("Output object currently has no stream");
        (*_os) << pf;
        return *this;
      }

      Output<T> & operator<<(std::ios & (*pf)(std::ios &)) {
        if ( _os.get() == 0 )
          throw formic::Exception("Output object currently has no stream");
        (*_os) << pf;
        return *this;
      }

      Output<T> & operator<<(std::ios_base & (*pf)(std::ios_base &)) {
        if ( _os.get() == 0 )
          throw formic::Exception("Output object currently has no stream");
        (*_os) << pf;
        return *this;
      }

      Output() {}

      Output(const boost::shared_ptr<T> & ptr) { _os = ptr; }

      ~Output() {
        if ( _os.get() != 0 )
          throw formic::Exception("Output object pointer was not empty upon destruction.");
      }

      void flush() {
        if ( _os.get() == 0 )
          throw formic::Exception("Output object currently has no stream");
        _os->flush();
      }

  };

  extern formic::Output<std::ofstream> of;

  void open_output_file(const std::string & filename);

  void close_output_file();

}

#endif
